package com.cy.security.config;


import com.cy.security.config.handler.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;

/**
 * 由@Configuration注解描述的类为spring中的配置类,配置类会在spring
 * 工程启动时优先加载,在配置类中通常会对第三方资源进行初始配置.
 *
 * 该@EnableGlobalMethodSecurity 注解由SpringSecurity提供,用于
 * 描述权限配置类,告诉系统底层在启动时,进行访问权限的初始化配置
 * 1)Enable-启用
 * 2)Global-全局
 * 3)Method-方法
 * 4)Security-安全
 */
//这个配置类是配置Spring-Security的,
//prePostEnabled= true表示启动权限管理功能
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    /**
     * 定义SpringSecurity密码加密对象
     * @Bean 注解通常会在@Configuration注解描述的类中描述方法,
     * 用于告诉spring框架这个方法的返回值会交给spring管理,并spring
     * 管理的这个对象起个默认的名字,这个名字与方法名相同,当然也可以通过
     * @Bean注解起名字
     */
    @Bean//对象名默认为方法名
    public PasswordEncoder passwordEncoder(){
        return new BCryptPasswordEncoder();
    }

    /**对http请求的安全控制进行配置*/
    @Override
    protected void configure(HttpSecurity http) throws Exception {
//        super.configure(http);
        //1.关闭跨域攻击，不关闭容易出错
        http.csrf().disable();
        //自定义登陆表单
        http.formLogin()
                //设置登陆页面
                .loginPage("/login.html")
                //设置登陆请求处理地址(对应form表单中的action),登陆时会访问UserDetailService对象
                .loginProcessingUrl("/login")
                //设置请求用户名参数为username(默认就是username，可以自己修改，需要与表单同步)
                .usernameParameter("username")
                //请求请求密码参数为password(默认就是password，可以自己修改，需要与表单同步)
                .passwordParameter("password")
//                设置登陆成功跳转页面(默认为/index.html)
//                .defaultSuccessUrl("/index.html") //登录成功的url(redirect)
//                .defaultSuccessUrl("https://www.baidu.com") //
//                .successForwardUrl("/index");//请求转发(controller中的一个方法)
                // 自定义登录成功处理器
//                .successHandler(new RedirectAuthenticationSuccessHandler("http://www.tedu.cn"))
                .successHandler(new DefaultAuthenticationSuccessHandler())
//                .failureHandler(new RedirectAuthenticationFailureHandler("http://www.tedu.cn"));
                .failureHandler(new DefaultAuthenticationFailureHandler());
                //登陆失败访问的页面（默认为/login.html?error）
//                .failureForwardUrl("/login.html?error");
        //认证设计
        http.authorizeRequests()
                //设置要放行的资源
//                “*”用于匹配0个或多个字符
//                “**”用于匹配0个或多个目录及字符
                .antMatchers( //配置下列路径的授权
                        "/login.html",
                        "/js/*",
                        "/css/*",
                        "/images/**",
                        "/index.html"
                ).permitAll()
                //设置需要认证的请求（除了上面的要放行，其它都要进行认证）
                .anyRequest().authenticated();
        // 登出设计及实现
        http.logout()
                .logoutUrl(".logout") //登出路径
                .logoutSuccessUrl("/login.html?logout");//设置登出后显示的页面
        //设置需要认证与拒绝访问的异常处理器
        http.exceptionHandling()
                .authenticationEntryPoint(//没有认证时执行DefaultAuthenticationEntryPoint对象
                        new DefaultAuthenticationEntryPoint())
                .accessDeniedHandler(//没有授权时执行DefaultAccessDeniedExceptionHandler对象
                        new DefaultAccessDeniedExceptionHandler());
    }

}
